home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 53142 / 53142.xpi / content / sorepdisplay.js < prev    next >
Text File  |  2009-12-07  |  13KB  |  347 lines

  1. /*##########################################################################
  2.     Copyright 2009 Tim Reid
  3.  
  4.     This file is part of the Stack Overflow Reputation Display extension
  5.     for Mozilla Firefox.
  6.  
  7.     Stack Overflow Reputation Display is free software: you can
  8.     redistribute it and/or modify it under the terms of the GNU General
  9.     Public License as published by the Free Software Foundation, either
  10.     version 3 of the License, or (at your option) any later version.
  11.  
  12.     Stack Overflow Reputation Display is distributed in the hope that it
  13.     will be useful, but WITHOUT ANY WARRANTY; without even the implied
  14.     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15.     See the GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public
  18.     License along with Stack Overflow Reputation Display. If not,
  19.     see <http://www.gnu.org/licenses/>.
  20. ##########################################################################*/
  21.  
  22. var sorepdisplay = {
  23.   myid:       "sorepdisplay@firefox.twistedlip.org",
  24.  
  25.   global:     {
  26.                 accounts: [],
  27.               },
  28.   displays:   null,
  29.   debug:      false,
  30.  
  31.   interfaces: {
  32.     prefs:   Components.classes["@mozilla.org/preferences-service;1"]
  33.                        .getService(Components.interfaces.nsIPrefService)
  34.                        .getBranch("extensions.sorepdisplay."),
  35.     sound:   Components.classes["@mozilla.org/sound;1"]
  36.                        .createInstance(Components.interfaces.nsISound),
  37.     wm:      Components.classes["@mozilla.org/appshell/window-mediator;1"]
  38.                        .getService(Components.interfaces.nsIWindowMediator),
  39.     console: Components.classes["@mozilla.org/consoleservice;1"]
  40.                        .getService(Components.interfaces.nsIConsoleService),
  41.   },
  42.  
  43.   observe: function (aSubject, aTopic, aData) {
  44.     if (aTopic == "nsPref:changed")  {
  45.       if (0) {
  46.       } else if (aData == "config") {
  47.         var newconfig = this.interfaces.prefs.getCharPref("config");
  48.         if (newconfig != this.global.currentconfig) {
  49.           //################################################################
  50.           // See below for why this setTimeout() is needed.
  51.           //################################################################
  52.           var me = this;
  53.           setTimeout(function () {
  54.                                    me.redoconfig(newconfig);
  55.                                    me.global.currentconfig = newconfig;
  56.                                  }, 1);
  57.         }
  58.       } else if (aData == "response") {
  59.         var responsetext = this.interfaces.prefs.getCharPref("response");
  60.         for (var i=0; i<this.global.accounts.length; i++)
  61.           this.global.accounts[i].handleresponse(responsetext);
  62.       } else if (aData == "reputationtextcolor") {
  63.         this.reputationtextcolor = this.interfaces.prefs.getCharPref("reputationtextcolor");
  64.         this.settextcolors();
  65.       } else if (aData == "badgetextcolor") {
  66.         this.badgetextcolor = this.interfaces.prefs.getCharPref("badgetextcolor");
  67.         this.settextcolors();
  68.       } else if (aData == "debug") {
  69.         this.debug = this.interfaces.prefs.getBoolPref("debug");
  70.         for (var i=0; i<this.global.accounts.length; i++)
  71.           this.global.accounts[i].debug = this.debug;
  72.       } else {
  73.         alert("Change in preference " + aData);
  74.       }
  75.     } else if (aTopic == "soaccount:scorechanged") {
  76.       if (this.debug)
  77.         this.interfaces.console.logStringMessage("SORepDisplay handling score change...");
  78.       for (var i=0; i<this.displays.length; i++)
  79.         if (this.displays[i].account === aSubject)
  80.           this.displays[i].updatedetails();
  81.     }
  82.   },
  83.  
  84. //##########################################################################
  85. // Why is the setTimeout() needed?
  86. // 
  87. // In its absence, when the configuration is changed using the preferences
  88. // dialog, the XMLHttpRequest objects generated during the redoconfig()
  89. // call get cancelled before they can complete. This is probably because
  90. // the observe() method is called by the same thread which is handling the
  91. // dialog interaction, but objects associated with that thread get taken
  92. // down when the dialog closes. Evidence supporting this explanation:
  93. // a delay introduced at *any* point between the XMLHttpRequest send()
  94. // call and the return from the observe() call is sufficient to allow the
  95. // XMLHttpRequest to complete correctly.
  96. // 
  97. // The workaround to this problem is to call the redoconfig() method as the
  98. // result of a setTimeout() call. This fixes the problem, probably because
  99. // it allows the XMLHttpRequest to be set up in a different context, and
  100. // therefore not cancelled.
  101. //##########################################################################
  102.  
  103.   doOptions: function () {
  104.     if (this.debug)
  105.       this.interfaces.console.logStringMessage("SORepDisplay opening configuration dialog...");
  106.     window.openDialog("chrome://sorepdisplay/content/options.xul",
  107.                       "options",
  108.                       "chrome,modal,centerscreen");
  109.   },
  110.  
  111.   launchtab: function (url) {
  112.     if (this.debug)
  113.       this.interfaces.console.logStringMessage("SORepDisplay opening new tab (" + url + ")...");
  114.     var numTabs = gBrowser.browsers.length;
  115.     for (var index = 0; index < numTabs; index++)
  116.       if (gBrowser.getBrowserAtIndex(index).currentURI.spec == url)
  117.         break;
  118.  
  119.     if (index < numTabs) {
  120.       gBrowser.selectedTab = gBrowser.tabContainer.childNodes[index];
  121.       gBrowser.getBrowserForTab(gBrowser.selectedTab).reload();
  122.     } else {
  123.       gBrowser.selectedTab = gBrowser.addTab(url);
  124.     }
  125.   },
  126.  
  127.   configureaccounts: function (config) {
  128.     var configparts = config.split(/,/);
  129.  
  130.     var soundbase   = "chrome://sorepdisplay/content/audio/";
  131.     var sounduris   = {
  132.                         up:   soundbase + "31189__acclivity__Triangle1.part.wav",
  133.                         down: soundbase + "66127__jobro__jobromedia_bullet_slowdown.lq.wav",
  134.                       };
  135.  
  136.     var accounts = [];
  137.     for (var i=0; i<configparts.length; i++) {
  138.       if (configparts[i][0] == "#")
  139.         continue;
  140.  
  141.       var account = new SOAccount(configparts[i]);
  142.       account.sounduris = sounduris;
  143.       account.debug = this.debug;
  144.       account.launchtimer();
  145.       account.addObserver(this);
  146.       accounts.push(account);
  147.     }
  148.  
  149.     return accounts;
  150.   },
  151.  
  152.   removedisplays: function () {
  153.     if (!this.displays)
  154.       return;
  155.  
  156.     while (this.displays.length > 0) {
  157.       var display = this.displays.shift();
  158.       display.elements.panel.parentNode.removeChild(display.elements.panel);
  159.       display.elements.popupset.parentNode.removeChild(display.elements.popupset);
  160.     }
  161.   },
  162.  
  163.   adddisplays: function (accounts) {
  164.     var displays = [];
  165.  
  166.     var insertpoint = document.getElementById("sorepdisplay-insertpoint");
  167.     var insertbefore = insertpoint.nextSibling;
  168.     for (var i=0; i<accounts.length; i++) {
  169.       var account = accounts[i];
  170.       var display = new SODisplay({
  171.                                     account: account,
  172.                                   });
  173.  
  174.       insertpoint.parentNode.insertBefore(display.elements.panel, insertbefore);
  175.       insertpoint.parentNode.insertBefore(display.elements.popupset, insertbefore);
  176.  
  177.       display.updatedetails();
  178.  
  179.       var me = this;
  180.       display.elements.menuitems.options.addEventListener("command", function (e) { me.doOptions(e); }, true);
  181.       display.registeropener(function (url) { me.launchtab(url); } );
  182.  
  183.       displays.push(display);
  184.     }
  185.  
  186.     return displays;
  187.   },
  188.  
  189.   removeaccounts: function () {
  190.     for (var i=0; i<this.global.accounts.length; i++)
  191.       this.global.accounts[i].cleartimer();
  192.     this.global.accounts = [];
  193.   },
  194.  
  195.   redoconfig: function (config) {
  196.     this.removeaccounts();
  197.     this.global.accounts = this.configureaccounts(config);
  198.     this.global.accountswantingpageloads = this.findaccountswantingpageloads();
  199.     var instances = this.findinstances();
  200.     for (var i=0; i<instances.length; i++) {
  201.       instances[i].removedisplays();
  202.       instances[i].displays = instances[i].adddisplays(this.global.accounts);
  203.       instances[i].initpageloads();
  204.     }
  205.   },
  206.  
  207.   findinstances: function () {
  208.     var instances = [];
  209.     var enumerator = this.interfaces.wm.getEnumerator("navigator:browser");  
  210.     while(enumerator.hasMoreElements()) {  
  211.       var win = enumerator.getNext();  
  212.       if (win.sorepdisplay)
  213.         instances.push(win.sorepdisplay);
  214.     } 
  215.  
  216.     return instances;
  217.   },
  218.  
  219.   findotherinstances: function () {
  220.     var candidates = this.findinstances();
  221.     var instances = [];
  222.     for (var i=0; i<candidates.length; i++)
  223.       if (candidates[i] !== this)
  224.         instances.push(candidates[i]);
  225.     return instances;
  226.   },
  227.  
  228.   pageload: function (e) {
  229.     var changed = false;
  230.     var candidates = this.global.accountswantingpageloads;
  231.     for (var i=0; i<candidates.length; i++)
  232.       changed = changed | candidates[i].pageload(e.originalTarget);
  233.     if (changed) {
  234.       this.global.currentconfig = this.config;
  235.       this.interfaces.prefs.setCharPref("config", this.global.currentconfig);
  236.  
  237.       this.global.accountswantingpageloads = this.findaccountswantingpageloads();
  238.       var instances = this.findinstances();
  239.       for (var i=0; i<instances.length; i++)
  240.         instances[i].initpageloads();
  241.     }
  242.   },
  243.  
  244.   initpageloads: function () {
  245.     var appcontent = document.getElementById("appcontent");
  246.     if(appcontent) {
  247.       var me = this;
  248.       if (this.global.accountswantingpageloads.length > 0) {
  249.         this.listener = function (e) { me.pageload(e); };
  250.         appcontent.addEventListener("DOMContentLoaded",
  251.                                     this.listener,
  252.                                     false);
  253.       } else {
  254.         appcontent.removeEventListener("DOMContentLoaded",
  255.                                        this.listener,
  256.                                        false);
  257.       }
  258.     }
  259.   },
  260.  
  261.   findaccountswantingpageloads: function () {
  262.     var accounts = []
  263.     for (var i=0; i<this.global.accounts.length; i++)
  264.       if (this.global.accounts[i].wantspageloads())
  265.         accounts.push(this.global.accounts[i]);
  266.     return accounts;
  267.   },
  268.  
  269.   enablesounds: function (b) {
  270.     for (var i=0; i<this.global.accounts.length; i++)
  271.       this.global.accounts[i].dosounds = b;
  272.  
  273.     var instances = this.findinstances();
  274.     for (var i=0; i<instances.length; i++)
  275.       for (var j=0; j<instances[i].displays.length; j++)
  276.         instances[i].displays[j].dosounds = b;
  277.   },
  278.  
  279.   soundmenu: function (e) {
  280.     var newvalue = e.target.getAttribute("checked") == "true";
  281.     this.interfaces.prefs.setBoolPref("soundeffects", newvalue);
  282.   },
  283.  
  284.   get config () {
  285.     var configs = [];
  286.     for (var i=0; i<this.global.accounts.length; i++)
  287.       configs.push(this.global.accounts[i].config);
  288.     return configs.join(",");
  289.   },
  290.  
  291.   close: function (e) {
  292.     for (var i=0; i<this.global.accounts.length; i++)
  293.       this.global.accounts[i].removeObserver(this);
  294.   },
  295.  
  296.   settextcolors: function () {
  297.     if (this.stylesheet) {
  298.       for (var i=0; i<this.stylesheet.cssRules.length; i++)
  299.         if (this.stylesheet.cssRules[i].type == CSSRule.STYLE_RULE &&
  300.             this.stylesheet.cssRules[i].selectorText == ".reputationtextcolor")
  301.           this.stylesheet.deleteRule(i);
  302.  
  303.       for (var i=0; i<this.stylesheet.cssRules.length; i++)
  304.         if (this.stylesheet.cssRules[i].type == CSSRule.STYLE_RULE &&
  305.             this.stylesheet.cssRules[i].selectorText == ".badgetextcolor")
  306.           this.stylesheet.deleteRule(i);
  307.  
  308.       this.stylesheet.insertRule(".reputationtextcolor { color: " + this.reputationtextcolor + "; }", 0);
  309.       this.stylesheet.insertRule(".badgetextcolor { color: " + this.badgetextcolor + "; }", 0);
  310.     }
  311.   },
  312.  
  313.   init: function (e) {
  314.     this.debug = this.interfaces.prefs.getBoolPref("debug");
  315.     this.reputationtextcolor = this.interfaces.prefs.getCharPref("reputationtextcolor");
  316.     this.badgetextcolor = this.interfaces.prefs.getCharPref("badgetextcolor");
  317.     var instances = this.findotherinstances();
  318.  
  319.     if (instances.length > 0) {
  320.       this.global = instances[0].global;
  321.     } else {
  322.       this.global.currentconfig            = this.interfaces.prefs.getCharPref("config");
  323.       this.global.accounts                 = this.configureaccounts(this.global.currentconfig);
  324.       this.global.accountswantingpageloads = this.findaccountswantingpageloads();
  325.     }
  326.  
  327.     this.removedisplays();
  328.     this.displays = this.adddisplays(this.global.accounts);
  329.     this.initpageloads();
  330.  
  331.     var me = this;
  332.  
  333.     this.interfaces.prefs.QueryInterface(Components.interfaces.nsIPrefBranch2);
  334.     this.interfaces.prefs.addObserver("", this, false);
  335.  
  336.     var stylesheets = document.styleSheets;
  337.     for (var i=0; i<stylesheets.length; i++)
  338.       if (stylesheets[i].href == "chrome://sorepdisplay/skin/sorepdisplay.css")
  339.         this.stylesheet = stylesheets[i];
  340.  
  341.     this.settextcolors();
  342.   },
  343. };
  344.  
  345. window.addEventListener("load",   function (e) { sorepdisplay.init(e); }, false);
  346. window.addEventListener("unload", function (e) { sorepdisplay.close(e); }, false);
  347.